pub mod cmd;
pub mod plc;

use base::{
    base::{VBase, VMap},
    err, err_value, ok, throw_err, ECode, MapSv, RNull, Resp, VecV,
};
use bytes::Bytes;
use plc::Plc;
use serde_json::{json, Value};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::Mutex;
use tracing::{instrument, warn};
use warp::{
    reject::Rejection,
    reply::{Json, WithStatus},
};

pub type ConTcp = Arc<Mutex<Box<Plc>>>;
pub type Connect = HashMap<String, ConTcp>;
pub type Seed = Arc<Mutex<i64>>;

#[instrument(skip_all, name = "s")]
pub async fn do_cmd(
    data: Bytes,
    plc: String,
    cmd: String,
    connect: &Connect,
    seed: Seed,
) -> Result<WithStatus<Json>, Rejection> {
    let val = match base::do_byte(data) {
        Ok(v) => v,
        Err(e) => {
            warn!("error val: {:?} - {:?} - {:?}", &e, plc, cmd);

            return Ok(base::ret_err(&e, None));
        }
    };

    let start = Instant::now();

    match cmd::doit(val, &plc, &cmd, connect, seed).await {
        Ok(v) => {
            let duration = start.elapsed();

            warn!(
                "dt: {:?} - end plc: {:?} - cmd: {:?} - val: {:?}",
                duration, plc, cmd, v
            );

            Ok(base::ret_ok(&v))
        }
        Err(e) => {
            let duration = start.elapsed();

            warn!(
                "dt: {:?} - error: {:?} - url: {:?} - cmd: {:?}",
                duration, &e, plc, cmd
            );

            Ok(base::ret_err(&e, None))
        }
    }
}
